package com.martin.lib_base.impl

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.martin.lib_base.interfaces.IRelease
import com.martin.lib_base.utils.ReleaseUtil
import com.martin.lib_base.utils.addReleaseForKey
import com.martin.lib_base.utils.releaseForLifecycle
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentHashMap

/**
 * 事件总线
 * Flow底层实现
 */
object FlowBus {

    // 总线map
    private val busMap = ConcurrentHashMap<Any, MutableSharedFlow<Any>>()

    // 粘性事件总线map
    private val busStickyMap = ConcurrentHashMap<Any, MutableSharedFlow<Any>>()

    /**
     * 根据Key获取事件总线
     */
    fun <T> with(key: String): MutableSharedFlow<T> {
        if (!busMap.containsKey(key)) {
            busMap[key] = MutableSharedFlow(0, 1, BufferOverflow.DROP_OLDEST)
        }
        return busMap[key] as MutableSharedFlow<T>
    }

    /**
     * 根据Key获取事件总线
     * 粘性事件需要发送及接收都使用才奏效
     */
    fun <T> withSticky(key: String): MutableSharedFlow<T> {
        if (!busStickyMap.containsKey(key)) {
            busStickyMap[key] = MutableSharedFlow(1, 1, BufferOverflow.DROP_OLDEST)
        }
        return busStickyMap[key] as MutableSharedFlow<T>
    }

}

/**
 * 观察者列表
 * 用于限制订阅次数
 */
private val observeList: HashMap<String, Job> = hashMapOf()

/**
 * 观察事件
 * 自动释放,根据生命周期自动释放资源
 */
fun <T> Flow<T>.observe(
    // 生命周期
    lifecycleOwner: LifecycleOwner,
    /**
     * 是否单次订阅
     * 仅取最后一次订阅事件
     */
    single: Boolean = true,
    // 订阅动作
    action: (T) -> Unit
) {
    val key = lifecycleOwner::class.java.simpleName + this.hashCode()

    // 防止重复订阅
    if (single) {
        observeList[key]?.cancel()
        observeList.remove(key)
    }

    // 接收事件
    val job: Job = lifecycleOwner.lifecycleScope.launch {
        collect { action(it) }
    }
    // 记录订阅
    if (single) {
        observeList[key] = job
    }
    // 释放资源
    object : IRelease {
        override fun release() {
            observeList.remove(key)
        }
    }.releaseForLifecycle(lifecycleOwner)
}

/**
 * 观察事件
 * 半自动释放,需要手动调用[ReleaseUtil.release]释放资源
 */
fun <T> MutableSharedFlow<T>.observeForKey(
    key: Any,
    scope: CoroutineScope = GlobalScope,
    action: (T) -> Unit
) {
    // 接收事件
    scope.launch {
        collect { action(it) }
    }.addReleaseForKey(key) {
        it.cancel()
    }
}
